package com.moshme.project.service.impl;

import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.moshme.common.exception.ServiceException;
import com.moshme.common.utils.SecurityUtils;
import com.moshme.common.utils.file.FileUtils;
import com.moshme.project.domain.File;
import com.moshme.project.domain.FileExample;
import com.moshme.project.domain.FileProject;
import com.moshme.project.mapper.FileMapper;
import com.moshme.project.service.FileExampleService;
import com.moshme.project.service.FileProjectService;
import com.moshme.project.service.FileService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Kieyfr
 * @description 针对表【file】的数据库操作Service实现
 * @createDate 2023/8/21 15:43
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    @Value("${moshme.profile}")
    private String storagePath;

    @Autowired
    private FileExampleService fileExampleService;

    @Autowired
    private FileProjectService fileProjectService;

    @Override
    public String upload(MultipartFile file, String path){
        if (file.isEmpty() || file.equals("") || file.getSize() <= 0) {
            throw new ServiceException("上传的文件为空");
        }
//        if (20 * 1024 * 1024 < file.getSize()) {
//            throw new ServiceException("上传的文件过大");
//        }
        // 文件原名
        String originalfileName = file.getOriginalFilename();
        if (StringUtils.isBlank(originalfileName)) {
            throw new ServiceException("文件名异常");
        }
        // 后缀名
        String suffixName = originalfileName.substring(originalfileName.lastIndexOf(".")).toLowerCase();
        String md5 = "";
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            md5 = SecureUtil.md5(inputStream);
        } catch (IOException e) {
            throw new ServiceException("获取文件MD5出错");
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        // MD5、大小、后缀相同的文件视为同一个文件
        LambdaQueryWrapper<File> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(File::getMd5, md5).eq(File::getType, suffixName).eq(File::getSize, file.getSize());
//        File data = getOne(lambdaQueryWrapper);
//        if (data!=null){
//            return data.getNetworkPath();
////            throw new ServiceException("文件不要重复上传");
//        }
        String newFileName = UUID.randomUUID() + suffixName;
//        String fileUploadPath = "/home/nginx/html/moshme/"+path;
        String fileUploadPath = storagePath + "/" + path + "/";
        java.io.File serverfile = new java.io.File(fileUploadPath);
        try {
            if (!serverfile.exists()) {
                serverfile.mkdirs();//创建目录
            }
            FileUtils.writeFile(file.getBytes(), fileUploadPath + newFileName);
        } catch (IOException e) {
            throw new ServiceException("文件上传失败");
        }
        File saveFile = new File();
        saveFile.setName(newFileName);
        saveFile.setOriginalName(originalfileName);
        saveFile.setType(suffixName);
        saveFile.setLocalPath(fileUploadPath + newFileName);
        String NetworkPath = "/profile/" + path + "/" + newFileName;
        saveFile.setNetworkPath(NetworkPath);
        saveFile.setSize(file.getSize());
        saveFile.setMd5(md5);
        save(saveFile);
        return saveFile.getNetworkPath();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized List<String> templateUpload(MultipartFile file, String path){
        LambdaQueryWrapper<FileExample> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<FileExample> eq = lambdaQueryWrapper.eq(FileExample::getFileTreePath, path);
        FileExample fileExample = fileExampleService.getOne(eq);
        List<String> fileList = new ArrayList<>();
        String networkPath = upload(file, path);
        if (fileExample != null) {
            List<String> oldFileList = fileExample.getFileList();
            for (String filePath : oldFileList) {
                fileList.add(filePath);
            }
            fileList.add(networkPath);
            fileExample.setFileList(fileList);
            fileExampleService.update(fileExample, eq);
        } else {
            fileList.add(networkPath);
            FileExample newFileExample = new FileExample();
            newFileExample.setFileTreePath(path);
            newFileExample.setFileList(fileList);
            fileExampleService.save(newFileExample);
        }
        return fileList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean templateDelete(String path) {
        LambdaQueryWrapper<File> fileLambdaQueryWrapper = new LambdaQueryWrapper<>();
        File file = getOne(fileLambdaQueryWrapper.eq(File::getNetworkPath, path));
        if (file == null) {
            throw new ServiceException("文件不存在");
        }
        remove(fileLambdaQueryWrapper.eq(File::getNetworkPath, path));
        String[] strings = path.split("/");
        String fileTreePath = "";
        for (int i = 0; i < strings.length; i++) {
            if (i >= 2 && i < strings.length - 2) {
                fileTreePath += strings[i] + "/";
            } else if (i == strings.length - 2) {
                fileTreePath += strings[i];
            }
        }
        LambdaQueryWrapper<FileExample> fileExampleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        FileExample fileExample = fileExampleService.getOne(fileExampleLambdaQueryWrapper.eq(FileExample::getFileTreePath, fileTreePath));
        List<String> fileList = fileExample.getFileList();
        if (fileList != null) {
            if (fileList.size() != 1) {
                List<String> list = fileList.stream().filter((String s) -> !s.equals(path)).collect(Collectors.toList());
                fileExample.setFileList(list);
                fileExampleService.update(fileExample, fileExampleLambdaQueryWrapper.eq(FileExample::getFileTreePath, fileTreePath));
            } else {
                fileExampleService.remove(fileExampleLambdaQueryWrapper.eq(FileExample::getFileTreePath, fileTreePath));
            }
        }
        java.io.File ioFile = new java.io.File(file.getLocalPath());
        if (ioFile.exists()) {
            if (!ioFile.delete()) {
                throw new ServiceException("文件删除失败");
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized List<String> projectUpload(MultipartFile file, String path, Long projectId, String longitude, String latitude){
        LambdaQueryWrapper<FileProject> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<FileProject> eq = lambdaQueryWrapper.eq(FileProject::getFileTreePath, path).eq(FileProject::getProjectId, projectId);
        FileProject fileProject = fileProjectService.getOne(eq);
        List<String> fileList = new ArrayList<>();
        List<String> longitudeList = new ArrayList<>();
        List<String> latitudeList = new ArrayList<>();
        String networkPath = upload(file, path);
        if (fileProject != null) {
            List<String> oldFileList = fileProject.getFileList();
            for (String filePath : oldFileList) {
                fileList.add(filePath);
            }
            fileList.add(networkPath);
            fileProject.setFileList(fileList);
            List<String> oldLongitudeList = fileProject.getLongitudeList();
            for (String longitudePath : oldLongitudeList) {
                longitudeList.add(longitudePath);
            }
            longitudeList.add(longitude);
            fileProject.setLongitudeList(longitudeList);
            List<String> oldLatitudeList = fileProject.getLatitudeList();
            for (String latitudePath : oldLatitudeList) {
                latitudeList.add(latitudePath);
            }
            latitudeList.add(latitude);
            fileProject.setLatitudeList(latitudeList);
            fileProjectService.update(fileProject, eq);
        } else {
            fileList.add(networkPath);
            longitudeList.add(longitude);
            latitudeList.add(latitude);
            FileProject newFileProject = new FileProject();
            newFileProject.setFileTreePath(path);
            newFileProject.setFileList(fileList);
            newFileProject.setLongitudeList(longitudeList);
            newFileProject.setLatitudeList(latitudeList);
            newFileProject.setProjectId(projectId);
            fileProjectService.save(newFileProject);
        }
        return fileList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean projectDelete(String path, Long projectId) {
        LambdaQueryWrapper<File> fileLambdaQueryWrapper = new LambdaQueryWrapper<>();
        File file = getOne(fileLambdaQueryWrapper.eq(File::getNetworkPath, path));
        if (file == null) {
            throw new ServiceException("文件不存在");
        }
        remove(fileLambdaQueryWrapper.eq(File::getNetworkPath, path));
        String[] strings = path.split("/");
        String fileTreePath = "";
        for (int i = 0; i < strings.length; i++) {
            if (i >= 2 && i < strings.length - 2) {
                fileTreePath += strings[i] + "/";
            } else if (i == strings.length - 2) {
                fileTreePath += strings[i];
            }
        }
        LambdaQueryWrapper<FileProject> fileProjectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        FileProject fileProject = fileProjectService.getOne(fileProjectLambdaQueryWrapper.eq(FileProject::getFileTreePath, fileTreePath).eq(FileProject::getProjectId, projectId));
        List<String> fileList = new ArrayList<>();
        List<String> longitudeList = new ArrayList<>();
        List<String> latitudeList = new ArrayList<>();
        fileList.addAll(fileProject.getFileList());
        longitudeList.addAll(fileProject.getLongitudeList());
        latitudeList.addAll(fileProject.getLatitudeList());
        if (fileList != null) {
            if (fileList.size() != 1) {
                for (int i = 0; i < fileList.size(); i++) {
                    if (fileList.get(i).equals(path)) {
                        fileList.remove(i);
                        longitudeList.remove(i);
                        latitudeList.remove(i);
                        fileProject.setFileList(fileList);
                        fileProject.setLongitudeList(longitudeList);
                        fileProject.setLatitudeList(latitudeList);
                        fileProjectService.update(fileProject, fileProjectLambdaQueryWrapper.eq(FileProject::getFileTreePath, fileTreePath).eq(FileProject::getProjectId, projectId));
                        break;
                    }
                }
            } else {
                fileProjectService.remove(fileProjectLambdaQueryWrapper.eq(FileProject::getFileTreePath, fileTreePath).eq(FileProject::getProjectId, projectId));
            }
        }
        java.io.File ioFile = new java.io.File(file.getLocalPath());
        if (ioFile.exists()) {
            if (!ioFile.delete()) {
                throw new ServiceException("文件删除失败");
            }
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delprojectAllFiles(Long projectId){
        String filePath = storagePath + "/项目/" + projectId + "/";
        java.io.File file = new java.io.File(filePath);
        if (file.exists()){
            LambdaUpdateWrapper<FileProject> fileProjectLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            fileProjectService.remove(fileProjectLambdaUpdateWrapper.eq(FileProject::getProjectId,projectId));
            LambdaUpdateWrapper<File> fileLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            remove(fileLambdaUpdateWrapper.like(File::getNetworkPath,"/profile/项目/" + projectId));
            Path path = Paths.get(filePath);
            try {
                Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                    // 先去遍历删除文件
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        Files.delete(file);
                        return FileVisitResult.CONTINUE;
                    }

                    // 再去遍历删除目录
                    @Override
                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                        Files.delete(dir);
                        return FileVisitResult.CONTINUE;
                    }

                });
            } catch (IOException e) {
                throw new ServiceException("文件删除失败");
            }
        }
        return true;
    }
}




